/*
 *    Copyright 2022 CManLH
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.lifeonwalden.ms.common.properties;

import com.lifeonwalden.ms.common.crypt.Rsa;
import com.lifeonwalden.ms.common.logger.LoggerUtil;
import org.apache.logging.log4j.Logger;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;

public class PropertyPlaceholder extends PropertySourcesPlaceholderConfigurer {
    private final static Logger logger = LoggerUtil.getLogger(PropertyPlaceholder.class);

    private static AtomicBoolean haveOne = new AtomicBoolean(false);

    private Properties properties = null;

    private boolean loadSystem = false;

    final static private String privateKey = "=-160=2Jggw=wAQAC=qkgBN=3bISGC=BEQAN=CSAAF=CCDYC=BIAXC=BGo=yrvl=Zpk6iC=6coo6C=cqy/tC=7tvw9C=7j2gED=/HjNZB=XCJ0kD=B/yjiD=F+GPjD=zK0bu=vQdkGB=L8Ah2C=YP+lsB=5GrIG=mzmrsD=Hrt4RC=kSSsk=hMY27=4tG9g=L3sn0D=IwOP9C=F1IWYB=CrooUB=wh9C2D=A12O1C=OZOJcB=zXVHg=PDlVVB=t9kPhD=V8+OG=+PsqRD=BMgAVD=BKQ=GGRRAC=ag0aAB=aXEXm=QcHUdD=bypa/D=jCeOxB=ixvmjD=IyZLhC=Uv+Nv=TLU/Z=a69e9=JWQ9eC=NWDSSD=3DwX3C=ZPwTJC=lAnYX=3cK8FB=6Obtd=OIpQPB=4ETweD=FWKdiB=NfexOD=1TtTzD=tJy7vC=ROlAzD=bo1js=8RWKCB=r9zf/C=UcHqFC=sj5h1B=I/fAzB=Dfy57C=AEkAdB=DdeueD=huMVRB=5yLubB=cL8uHD=GPjDKC=FvH9hD=2ocAkB=Pfl2j=FMZuPB=oRcw8D=8WDIHB=KeL39C=O5nwX=GI2REC=oT1NxB=naycDC=tCQQC=cBKJJC=r+muhC=JtZ0sC=l7zu0=QAExcD=mTLmvB=CDSNL=JKg1YB=+xHopB=6sYXcC=5gIYd=3MHYnD=N3UL1D=+nMEu=ywxr0B=CMiW5D=5ACMAB=KSWahB=nMpjv=QUUesB=C/W+=qqkWu=fk05nC=DvRf5C=JGujXD=VZMRsB=2soN7C=mE1Vx=2itlzD=S8mHUD=hZCV2=kXDcZC=4BkAHC=eB1hCB=7sbcBC=rmwqED=4JN0EB=XVlcnD=mwwjOB=8BC9z=ijbpuC=kVfgTB=7ripkC=dyqKe=coFH8=Eo0WYC=OSQ/7B=VrCfDD=CMfekC=5+JABB=ywJqeC=57rSyC=tU/EwC=axrROC=5J9dfC=oodZw=xfbkbD=hluEbB=TRJkk=a8xefC=KuO+3D=fPv+LC=KxW0F=ypbBmD=iHWxWD=W+///D=E////D";
    final static private String publicKey = "=-42=w8Zgw=qkgBN=3bISGC=BEQAN=BOAAF=BCDANC=BGoAJC=yrvl=Zpk6iC=6coo6C=cqy/tC=7tvw9C=7j2gED=/HjNZB=XCJ0kD=B/yjiD=F+GPjD=zK0bu=vQdkGB=L8Ah2C=YP+lsB=5GrIG=mzmrsD=Hrt4RC=kSSsk=hMY27=4tG9g=L3sn0D=IwOP9C=F1IWYB=CrooUB=wh9C2D=A12O1C=OZOJcB=zXVHg=PDlVVB=t9kPhD=V8+OG=+PsqRD=BMgAVD=A=B";

    public PropertyPlaceholder() {
        if (haveOne.get()) {
            throw new RuntimeException("Error happened when starting spring application to cause reloading the property configuration. Please resolve the starting error and then restart the application.");
        } else {
            haveOne.set(true);
        }
    }

    // ONE TIME JOB, NOT THREAD SAFE
    public String getProperty(String key) {
        if (null == properties) {
            try {
                properties = super.mergeProperties();
                if (loadSystem) {
                    Properties props = System.getProperties();
                    Enumeration<?> enumNames = props.propertyNames();
                    while (enumNames.hasMoreElements()) {
                        Object name = enumNames.nextElement();
                        if (name != null) {
                            String value = (String) props.get(name);
                            if (value.toLowerCase().startsWith("_mix_|")) {
                                properties.put(name, Rsa.decrypt(privateKey, value.substring(6)));
                            } else {
                                properties.put(name, props.get(name));
                            }
                        }
                    }
                }
            } catch (IOException e) {
                logger.error("Failed to load properties file.", e);
            }
        }
        if (null != properties) {
            return properties.getProperty(key);
        } else {
            return null;
        }
    }

    public void setLoadSystem(boolean loadSystem) {
        this.loadSystem = loadSystem;
    }

    @Override
    protected void loadProperties(Properties props) throws IOException {
        super.loadProperties(props);

        Enumeration<?> enumNames = props.propertyNames();
        while (enumNames.hasMoreElements()) {
            Object name = enumNames.nextElement();
            if (name != null) {
                String value = (String) props.get(name);
                if (value.toLowerCase().startsWith("_mix_|")) {
                    props.put(name, Rsa.decrypt(privateKey, value.substring(6)));
                } else {
                    props.put(name, props.get(name));
                }
            }
        }
    }

    public static void main(String[] args) {
        if (null != args && args.length > 0) {
            if (1 == args.length) {
                System.out.printf("Password is : %s", args[0]);
                String p = Rsa.encrypt(publicKey, args[0]);
                System.out.printf("Encrypted is : %s", p);
            } else if ("Decrypt".equals(args[1])) {
                String p = Rsa.decrypt(privateKey, args[0]);
                System.out.printf("Password is : %s", p);
            }
        }
    }
}
